//! CLUSTER命令单元测试
//! 
//! 测试CLUSTER协议解析器和命令处理功能，包括：
//! - ClusterProtocolParser的命令解析
//! - CLUSTER子命令的参数验证
//! - RESP协议响应格式化
//! - 集群命令的错误处理
//! - 槽位计算和管理

use redis_rs2::cluster::{ClusterProtocolParser, RedisClusterCommand, ClusterCommandResult, ClusterError};

#[cfg(test)]
mod cluster_protocol_parser_tests {
    use super::*;
    
    #[test]
    fn test_parse_cluster_nodes() {
        let args = vec!["NODES".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER NODES命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::Nodes => {},
            _ => panic!("应该解析为Nodes命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_info() {
        let args = vec!["INFO".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER INFO命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::Info => {},
            _ => panic!("应该解析为Info命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_slots() {
        let args = vec!["SLOTS".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER SLOTS命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::Slots => {},
            _ => panic!("应该解析为Slots命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_myid() {
        let args = vec!["MYID".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER MYID命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::MyId => {},
            _ => panic!("应该解析为MyId命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_keyslot() {
        let args = vec!["KEYSLOT".to_string(), "testkey".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER KEYSLOT命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::KeySlot { key } => {
                assert_eq!(key, "testkey", "键名应该正确解析");
            },
            _ => panic!("应该解析为KeySlot命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_meet() {
        let args = vec!["MEET".to_string(), "127.0.0.1".to_string(), "7000".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER MEET命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::Meet { ip, port } => {
                assert_eq!(ip, "127.0.0.1", "IP地址应该正确解析");
                assert_eq!(port, 7000, "端口应该正确解析");
            },
            _ => panic!("应该解析为Meet命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_addslots() {
        let args = vec!["ADDSLOTS".to_string(), "0".to_string(), "1".to_string(), "2".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER ADDSLOTS命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::AddSlots { slots } => {
                assert_eq!(slots, vec![0, 1, 2], "槽位列表应该正确解析");
            },
            _ => panic!("应该解析为AddSlots命令"),
        }
    }
    
    #[test]
    fn test_parse_cluster_setslot() {
        let args = vec!["SETSLOT".to_string(), "123".to_string(), "MIGRATING".to_string(), "node1".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_ok(), "CLUSTER SETSLOT命令解析应该成功");
        match result.unwrap() {
            RedisClusterCommand::SetSlot { slot, subcommand, node_id } => {
                assert_eq!(slot, 123, "槽位号应该正确解析");
                assert_eq!(subcommand, "MIGRATING", "子命令应该正确解析");
                assert_eq!(node_id, Some("node1".to_string()), "节点ID应该正确解析");
            },
            _ => panic!("应该解析为SetSlot命令"),
        }
    }
}

#[cfg(test)]
mod cluster_parser_error_tests {
    use super::*;
    
    #[test]
    fn test_parse_empty_command() {
        let args: Vec<String> = vec![];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "空命令应该返回错误");
        match result.unwrap_err() {
            ClusterError::Config(msg) => {
                assert!(msg.contains("requires subcommand"), "错误消息应该提示需要子命令");
            },
            _ => panic!("应该返回Config错误"),
        }
    }
    
    #[test]
    fn test_parse_unknown_subcommand() {
        let args = vec!["UNKNOWN".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "未知子命令应该返回错误");
    }
    
    #[test]
    fn test_parse_meet_missing_args() {
        let args = vec!["MEET".to_string(), "127.0.0.1".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "MEET命令缺少参数应该返回错误");
    }
    
    #[test]
    fn test_parse_meet_invalid_port() {
        let args = vec!["MEET".to_string(), "127.0.0.1".to_string(), "invalid_port".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "无效端口号应该返回错误");
    }
    
    #[test]
    fn test_parse_keyslot_missing_key() {
        let args = vec!["KEYSLOT".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "KEYSLOT命令缺少键参数应该返回错误");
    }
    
    #[test]
    fn test_parse_addslots_no_slots() {
        let args = vec!["ADDSLOTS".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "ADDSLOTS命令没有槽位应该返回错误");
    }
    
    #[test]
    fn test_parse_addslots_invalid_slot() {
        let args = vec!["ADDSLOTS".to_string(), "invalid_slot".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "无效槽位号应该返回错误");
    }
    
    #[test]
    fn test_parse_addslots_out_of_range() {
        let args = vec!["ADDSLOTS".to_string(), "16384".to_string()]; // 超出范围
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "超出范围的槽位号应该返回错误");
    }
    
    #[test]
    fn test_parse_setslot_missing_args() {
        let args = vec!["SETSLOT".to_string(), "123".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "SETSLOT命令缺少参数应该返回错误");
    }
    
    #[test]
    fn test_parse_nodes_with_args() {
        let args = vec!["NODES".to_string(), "extra_arg".to_string()];
        let result = ClusterProtocolParser::parse_cluster_command(&args);
        
        assert!(result.is_err(), "NODES命令带有额外参数应该返回错误");
    }
}

#[cfg(test)]
mod cluster_response_format_tests {
    use super::*;
    
    #[test]
    fn test_format_simple_string() {
        let result = ClusterCommandResult::SimpleString("OK".to_string());
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, "+OK\r\n", "SimpleString响应格式应该正确");
    }
    
    #[test]
    fn test_format_bulk_string() {
        let result = ClusterCommandResult::BulkString("hello world".to_string());
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, "$11\r\nhello world\r\n", "BulkString响应格式应该正确");
    }
    
    #[test]
    fn test_format_empty_bulk_string() {
        let result = ClusterCommandResult::BulkString("".to_string());
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, "$0\r\n\r\n", "空BulkString响应格式应该正确");
    }
    
    #[test]
    fn test_format_integer() {
        let result = ClusterCommandResult::Integer(42);
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, ":42\r\n", "Integer响应格式应该正确");
    }
    
    #[test]
    fn test_format_negative_integer() {
        let result = ClusterCommandResult::Integer(-1);
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, ":-1\r\n", "负整数响应格式应该正确");
    }
    
    #[test]
    fn test_format_array() {
        let result = ClusterCommandResult::Array(vec![
            "item1".to_string(),
            "item2".to_string(),
            "item3".to_string(),
        ]);
        let response = ClusterProtocolParser::format_cluster_response(&result);
        let expected = "*3\r\n$5\r\nitem1\r\n$5\r\nitem2\r\n$5\r\nitem3\r\n";
        assert_eq!(response, expected, "Array响应格式应该正确");
    }
    
    #[test]
    fn test_format_empty_array() {
        let result = ClusterCommandResult::Array(vec![]);
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, "*0\r\n", "空Array响应格式应该正确");
    }
    
    #[test]
    fn test_format_error() {
        let result = ClusterCommandResult::Error("Something went wrong".to_string());
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, "-ERR Something went wrong\r\n", "Error响应格式应该正确");
    }
    
    #[test]
    fn test_format_null() {
        let result = ClusterCommandResult::Null;
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert_eq!(response, "$-1\r\n", "Null响应格式应该正确");
    }
}

#[cfg(test)]
mod cluster_keyslot_tests {
    use super::*;
    
    /// 模拟CRC16槽位计算（简化版）
    fn calculate_slot(key: &str) -> u16 {
        let mut crc: u16 = 0;
        for byte in key.bytes() {
            crc = crc.wrapping_add(byte as u16);
        }
        crc % 16384
    }
    
    #[test]
    fn test_keyslot_calculation() {
        // 测试基本键的槽位计算
        let test_cases = vec![
            ("test", calculate_slot("test")),
            ("user:1000", calculate_slot("user:1000")),
            ("session:abc123", calculate_slot("session:abc123")),
        ];
        
        for (key, expected_slot) in test_cases {
            let calculated = calculate_slot(key);
            assert_eq!(calculated, expected_slot, "键 '{}' 的槽位计算应该一致", key);
            assert!(calculated < 16384, "槽位号应该在有效范围内");
        }
    }
    
    #[test]
    fn test_keyslot_edge_cases() {
        // 测试边界情况
        let edge_cases = vec![
            "",           // 空键
            " ",          // 空格
            "a",          // 单字符
            "🔑",          // Unicode
            "very_long_key_name_that_exceeds_normal_length_expectations_and_continues_for_a_while",
        ];
        
        for key in edge_cases {
            let slot = calculate_slot(key);
            assert!(slot < 16384, "边界情况键 '{}' 的槽位应该在有效范围内", key);
        }
    }
    
    #[test]
    fn test_keyslot_consistency() {
        // 测试相同键的一致性
        let key = "consistency_test";
        let slot1 = calculate_slot(key);
        let slot2 = calculate_slot(key);
        let slot3 = calculate_slot(key);
        
        assert_eq!(slot1, slot2, "相同键的槽位计算应该一致");
        assert_eq!(slot2, slot3, "相同键的槽位计算应该一致");
    }
    
    #[test]
    fn test_keyslot_distribution() {
        // 测试槽位分布的基本属性
        let mut slot_counts = vec![0; 16384];
        
        // 生成一些测试键并计算它们的槽位
        for i in 0..10000 {
            let key = format!("test_key_{}", i);
            let slot = calculate_slot(&key) as usize;
            slot_counts[slot] += 1;
        }
        
        // 检查是否有槽位被使用
        let used_slots = slot_counts.iter().filter(|&&count| count > 0).count();
        assert!(used_slots > 1000, "应该有足够多的槽位被使用以确保分布");
        
        // 检查没有槽位过度集中
        let max_count = *slot_counts.iter().max().unwrap();
        assert!(max_count < 100, "没有槽位应该过度集中");
    }
}

#[cfg(test)]
mod cluster_command_integration_tests {
    use super::*;
    
    #[test]
    fn test_cluster_info_command_flow() {
        // 测试完整的CLUSTER INFO命令流程
        let args = vec!["INFO".to_string()];
        
        // 1. 解析命令
        let command = ClusterProtocolParser::parse_cluster_command(&args).unwrap();
        assert!(matches!(command, RedisClusterCommand::Info));
        
        // 2. 模拟命令执行结果
        let result = ClusterCommandResult::BulkString(
            "cluster_state:ok\ncluster_slots_assigned:16384\ncluster_known_nodes:1".to_string()
        );
        
        // 3. 格式化响应
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert!(response.starts_with("$"));
        assert!(response.contains("cluster_state:ok"));
    }
    
    #[test]
    fn test_cluster_slots_command_flow() {
        // 测试完整的CLUSTER SLOTS命令流程
        let args = vec!["SLOTS".to_string()];
        
        // 1. 解析命令
        let command = ClusterProtocolParser::parse_cluster_command(&args).unwrap();
        assert!(matches!(command, RedisClusterCommand::Slots));
        
        // 2. 模拟槽位分配结果
        let slots_response = vec![
            "0".to_string(),
            "16383".to_string(),
            "127.0.0.1:6379".to_string(),
        ];
        let result = ClusterCommandResult::Array(slots_response);
        
        // 3. 格式化响应
        let response = ClusterProtocolParser::format_cluster_response(&result);
        assert!(response.starts_with("*3"));
        assert!(response.contains("16383"));
        assert!(response.contains("127.0.0.1:6379"));
    }
    
    #[test]
    fn test_error_command_flow() {
        // 测试错误命令的完整流程
        let args = vec!["INVALID".to_string()];
        
        // 1. 解析命令（应该失败）
        let parse_result = ClusterProtocolParser::parse_cluster_command(&args);
        assert!(parse_result.is_err());
        
        // 2. 格式化错误响应
        let error_result = ClusterCommandResult::Error("Unknown CLUSTER subcommand: INVALID".to_string());
        let response = ClusterProtocolParser::format_cluster_response(&error_result);
        assert_eq!(response, "-ERR Unknown CLUSTER subcommand: INVALID\r\n");
    }
}